home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / program / swags_z.zip / STREAMS.SWG / 0004_Stream Storage Unit.pas < prev    next >
Pascal/Delphi Source File  |  1995-03-03  |  25KB  |  705 lines

  1.  
  2. Unit Storage;
  3.  
  4. {  STORAGE.PAS - 13 Jan 91
  5.  
  6.    This unit was created to replace the original system storage that was
  7.    created for the DMG.  It is designed to be object oriented and will
  8.    also alow for external compression routines to be designed into the
  9.    system with a registration code for each.
  10.  
  11.    The system will take a buffer pointer and run it through the compressor
  12.    until it reaches a NULL (0) character in the buffer.  This limits you
  13.    to storing only readable messages.  Once the compressor is finished,
  14.    the resulting bitstream is then written to the disk.  An index number
  15.    is returned for where this was written.
  16.  
  17.    The system that reads the messages only needs an index and filename.
  18.    It will create a buffer for the message up to the memory restraints.
  19.  
  20.    You MUST do a .done when you are through with the buffer or the space
  21.    will not be released to the heap.
  22.  
  23.    NOTES:
  24.       The compression algorythm on this system is VERY rudimentary and is
  25.       designed for text only type of material.  It strips all spaces out of
  26.       your text and compresses the next character with 128.  This generally
  27.       saves around 20% storage of a typical text file.  The other change
  28.       is to do the same with the lower case 'e' character.  This is then
  29.       combined with a 64.  Between the two you get around %30 compression
  30.       on your text files... Pretty nifty...
  31.  
  32.       Note that there is no modifications or remaps of any character ranging
  33.       from 000..159.  This is so that you can take a standard FIDO file and
  34.       read it without remapping the soft carriage returns and linefeeds
  35.       (8D and 8A).
  36.  
  37. }
  38.  
  39. {$F+,O+,S-,R-}
  40.  
  41. Interface
  42.  
  43. Uses Dos, Objects;
  44.  
  45. CONST stStoreError      = -120;
  46.       stStoreReadErr    = 197;
  47.       stStoreWriteErr   = 198;
  48.       stStoreUnknownErr = 199;
  49.  
  50. TYPE  PBuffer  = ^BBuffer;
  51.       BBuffer  = ARRAY [0..65530] OF BYTE;
  52.       PCharBuf = ^CharBuf;
  53.       CharBuf  = ARRAY [0..65530] OF CHAR;
  54.  
  55. TYPE  PList    = ^LList;
  56.       LList    = RECORD
  57.                     OldItem : LONGINT;
  58.                     NewItem : LONGINT;
  59.                     Next    : PList;
  60.                  END;
  61.  
  62. TYPE  PStorage = ^TStorage;
  63.       TStorage = OBJECT(TBufStream)
  64.                     SFileName   : FNameStr;
  65.                     SCleanName  : FNameStr;
  66.                     SCleanIndex : PList;
  67.                     SMode       : WORD;
  68.                     SIndex      : LONGINT;
  69.                     SHoldBuf    : POINTER;
  70.                     SHoldBufLen : WORD;
  71.                     CONSTRUCTOR Init(AFileName : FNameStr; AMode, Size : WORD);
  72.                     PROCEDURE WriteMsg(VAR Buf);
  73.                     PROCEDURE ReadMsg(VAR Buf : PCharBuf; Index : LONGINT);
  74.                     PROCEDURE DeleteMsg(Index : LONGINT);
  75.                     PROCEDURE CleanUpMsg;
  76.                     FUNCTION NewIndex(Index : LONGINT) : LONGINT;
  77.                     PROCEDURE DeleteCleanUp;
  78.                     PROCEDURE Compress(VAR Buf); VIRTUAL;
  79.                     PROCEDURE DeCompress(VAR Buf); VIRTUAL;
  80.                     DESTRUCTOR Done; VIRTUAL;
  81.                  END;
  82.  
  83. Implementation
  84.  
  85. CONST MarkerWord   = $93D2;
  86.       RegBasicComp : BYTE = $01;
  87.  
  88. VAR   ExpandSize   : WORD;
  89.       CompressSize : WORD;
  90.       Marker       : WORD;
  91.  
  92. {----------------------------------------------------------------------------}
  93.  
  94. CONSTRUCTOR TStorage.Init;
  95. BEGIN
  96.    TBufStream.Init(AFileName,AMode,Size);
  97.    IF Status <> stOk THEN
  98.       Status := stStoreError
  99.    ELSE
  100.       BEGIN
  101.          SFileName   := FEXPAND(AFileName);
  102.          SCleanName  := '';
  103.          SCleanIndex := NIL;
  104.          SMode       := AMode;
  105.          SIndex      := 0;
  106.          SHoldBuf    := NIL;
  107.          SHoldBufLen := 0
  108.       END
  109. END;
  110.  
  111. {----------------------------------------------------------------------------}
  112.  
  113. PROCEDURE TStorage.WriteMsg;
  114. VAR   WritePosn    : WORD;
  115.       p            : PBuffer;
  116. BEGIN
  117.    p := PBuffer(@Buf);
  118.    SIndex := GetSize;
  119.    TBufStream.Seek(SIndex);
  120.    Marker := MarkerWord;
  121.    TBufStream.Write(Marker,SIZEOF(Marker));
  122.    ExpandSize := 0;
  123.    WHILE (p^[ExpandSize] <> 0) DO
  124.       INC(ExpandSize);
  125.    TBufStream.Write(ExpandSize,SIZEOF(ExpandSize));
  126.    Compress(Buf);
  127.    CompressSize := 0;
  128.    WHILE (p^[CompressSize] <> 0) DO
  129.       INC(CompressSize);
  130.    TBufStream.Write(CompressSize,SIZEOF(CompressSize));
  131.    WritePosn := 0;
  132.    WHILE WritePosn < CompressSize DO
  133.       IF CompressSize - WritePosn > BufSize THEN
  134.          BEGIN
  135.             TBufStream.Write(p^[WritePosn],BufSize);
  136.             INC(WritePosn,BufSize)
  137.          END
  138.       ELSE
  139.          BEGIN
  140.             TBufStream.Write(p^[WritePosn],CompressSize - WritePosn);
  141.             WritePosn := CompressSize
  142.          END;
  143.    Flush;
  144.    IF Status <> stOk THEN
  145.       Status := stStoreError
  146. END;
  147.  
  148. {----------------------------------------------------------------------------}
  149.  
  150. PROCEDURE TStorage.ReadMsg;
  151. VAR   DeleteCheck : BYTE;
  152. BEGIN
  153.    IF (SHoldBuf <> NIL) AND (SHoldBufLen > 0) THEN
  154.       BEGIN
  155.          FREEMEM(SHoldBuf,SHoldBufLen);
  156.          SHoldBuf := NIL;
  157.          SHoldBufLen := 0
  158.       END;
  159.    Seek(Index);
  160.    Read(Marker,SIZEOF(Marker));
  161.    IF Marker = MarkerWord THEN
  162.       BEGIN
  163.          Read(ExpandSize,SIZEOF(ExpandSize));
  164.          Read(CompressSize,SIZEOF(CompressSize));
  165.       END
  166.    ELSE
  167.       BEGIN
  168.          Seek(Index);
  169.          ExpandSize := GetSize - Index;
  170.          IF ExpandSize >= SIZEOF(CharBuf) THEN
  171.             ExpandSize := SIZEOF(CharBuf) - 1;
  172.          CompressSize := ExpandSize
  173.       END;
  174.    Read(DeleteCheck,1);
  175.    IF (DeleteCheck < $FF) OR (Marker <> MarkerWord) THEN
  176.       BEGIN
  177.          SHoldBufLen := ExpandSize + 1;
  178.          GETMEM(SHoldBuf,SHoldBufLen);
  179.          FILLCHAR(SHoldBuf^,SHoldBufLen,0);
  180.          BBuffer(SHoldBuf^)[0] := DeleteCheck;
  181.          Read(BBuffer(SHoldBuf^)[1],CompressSize - 1);
  182.          IF Marker = MarkerWord THEN
  183.             DeCompress(SHoldBuf^);
  184.       END
  185.    ELSE
  186.       BEGIN
  187.          SHoldBufLen := 1;
  188.          GETMEM(SHoldBuf,1);
  189.          BBuffer(SHoldBuf^)[0] := 0;
  190.          Error(stStoreError,stStoreReadErr)     {Disk Read Error}
  191.       END;
  192.    PCharBuf(Buf) := @SholdBuf^;
  193.    IF Status <> stOk THEN
  194.       Status := stStoreError
  195. END;
  196.  
  197. {----------------------------------------------------------------------------}
  198.  
  199. PROCEDURE TStorage.DeleteMsg;
  200. VAR   CompressType : BYTE;
  201. BEGIN
  202.    Seek(Index);
  203.    Read(Marker,SIZEOF(Marker));
  204.    IF Marker = MarkerWord THEN
  205.       BEGIN
  206.          Seek(Index + SIZEOF(Marker) + SIZEOF(ExpandSize) + SIZEOF(CompressSize));
  207.          CompressType := $FF;   {Mark Compression Type as Deleted!}
  208.          Write(CompressType,SIZEOF(CompressType))
  209.       END;
  210.    IF Status <> stOk THEN
  211.       Status := stStoreError
  212. END;
  213.  
  214. {----------------------------------------------------------------------------}
  215.  
  216. PROCEDURE TStorage.CleanUpMsg;
  217. VAR   Dir     : DirStr;
  218.       FName   : NameStr;
  219.       Ext     : ExtStr;
  220.       T       : TBufStream;
  221.       TmpPtr  : POINTER;
  222.       TFile   : FILE;
  223.       OldItem : LONGINT;
  224.       NewItem : LONGINT;
  225.       LinkPtr : PList;
  226. BEGIN
  227.    FSplit(SFileName,Dir,FName,Ext);
  228.    SCleanName := Dir + FName + '.$$$';
  229.    T.Init(SCleanName,stCreate,1024);
  230.    Seek(0);
  231.    OldItem := 0;
  232.    WHILE OldItem < GetSize - 1 DO BEGIN
  233.       Read(Marker,SIZEOF(Marker));
  234.       IF Marker <> MarkerWord THEN
  235.          Error(stStoreError,stStoreUnknownErr);
  236.       Read(ExpandSize,SIZEOF(ExpandSize));
  237.       Read(CompressSize,SIZEOF(CompressSize));
  238.       GETMEM(TmpPtr,CompressSize);
  239.       Read(TmpPtr^,CompressSize);
  240.       IF (Status = stOk) AND (BBuffer(TmpPtr^)[0] < $FF) THEN
  241.          BEGIN
  242.             NewItem := T.GetPos;
  243.             T.Write(Marker,SIZEOF(Marker));
  244.             T.Write(ExpandSize,SIZEOF(ExpandSize));
  245.             T.Write(CompressSize,SIZEOF(CompressSize));
  246.             T.Write(TmpPtr^,CompressSize);
  247.             GETMEM(LinkPtr,SIZEOF(LList));
  248.             LinkPtr^.OldItem := OldItem;
  249.             LinkPtr^.NewItem := NewItem;
  250.             LinkPtr^.Next := SCleanIndex;
  251.             SCleanIndex := LinkPtr
  252.          END;
  253.       FREEMEM(TmpPtr,CompressSize);
  254.       OldItem := GetPos
  255.    END;
  256.    T.Done;
  257.    IF Status <> stOk THEN
  258.       BEGIN
  259.          ASSIGN(TFile,SCleanName);
  260.          ERASE(TFile);
  261.          SCleanName := '';
  262.          Status := stStoreError
  263.       END
  264. END;
  265.  
  266. {----------------------------------------------------------------------------}
  267.  
  268. FUNCTION TStorage.NewIndex;
  269. VAR   PLink : PList;
  270. BEGIN
  271.    PLink := SCleanIndex;
  272.    NewIndex := -1;
  273.    WHILE (PLink <> NIL) AND (PLink^.OldItem <> Index) DO
  274.       PLink := PLink^.Next;
  275.    IF (PLink <> NIL) AND (PLink^.OldItem = Index) THEN
  276.       NewIndex := PLink^.NewItem
  277. END;
  278.  
  279. {----------------------------------------------------------------------------}
  280.  
  281. PROCEDURE TStorage.DeleteCleanUp;
  282. VAR   TFile : FILE;
  283.       PLink : PList;
  284. BEGIN
  285.    IF SCleanName <> '' THEN
  286.       BEGIN
  287.          {$I-} ASSIGN(TFile,SCleanName);
  288.          ERASE(TFile); {$I+}
  289.          ErrorInfo := IOResult;
  290.          IF ErrorInfo <> stOk THEN
  291.             Status := stStoreError;
  292.          SCleanName := '';
  293.          WHILE SCleanIndex <> NIL DO BEGIN
  294.             PLink := SCleanIndex;
  295.             SCleanIndex := PLink^.Next;
  296.             FREEMEM(PLink,SIZEOF(LList))
  297.          END
  298.       END
  299. END;
  300.  
  301. {----------------------------------------------------------------------------}
  302.  
  303. PROCEDURE TStorage.Compress;
  304. VAR   p          : PBuffer;
  305.       ReadPosn   : WORD;
  306.       WritePosn  : WORD;
  307.       SpaceCount : WORD;
  308. BEGIN
  309.    p := PBuffer(@Buf);
  310.    ReadPosn := 0;
  311.    WritePosn := 0;
  312.    WHILE (p^[ReadPosn] <> 0) AND (ReadPosn < 65530) DO BEGIN
  313.       SpaceCount := 0;
  314.       WHILE (p^[ReadPosn + SpaceCount] = 32) DO
  315.          INC(SpaceCount);
  316.       IF SpaceCount > 1 THEN
  317.          BEGIN
  318.             INC(ReadPosn,SpaceCount);
  319.             WHILE SpaceCount > 0 DO
  320.                IF SpaceCount > 255 THEN
  321.                   BEGIN
  322.                      p^[WritePosn] := 255;
  323.                      p^[WritePosn + 1] := 255;
  324.                      INC(WritePosn,2);
  325.                      DEC(SpaceCount,255)
  326.                   END
  327.                ELSE
  328.                   BEGIN
  329.                      p^[WritePosn] := 255;
  330.                      p^[WritePosn + 1] := SpaceCount;
  331.                      INC(WritePosn,2);
  332.                      SpaceCount := 0
  333.                   END;
  334.             SpaceCount := 2
  335.          END;
  336.       IF SpaceCount = 1 THEN
  337.          IF (p^[ReadPosn + 1] >= 64) AND (p^[ReadPosn + 1] <= 127) THEN
  338.             BEGIN
  339.                p^[WritePosn] := p^[ReadPosn + 1] + 128;
  340.                INC(WritePosn);
  341.                INC(ReadPosn,2)
  342.             END
  343.          ELSE
  344.             SpaceCount := 0;
  345.       IF SpaceCount = 0 THEN
  346.          BEGIN
  347.             IF p^[ReadPosn + 1] = 101 THEN
  348.                BEGIN
  349.                   p^[WritePosn] := p^[ReadPosn] + 64;
  350.                   INC(ReadPosn,2)
  351.                END
  352.             ELSE
  353.                BEGIN
  354.                   p^[WritePosn] := p^[ReadPosn];
  355.                   INC(ReadPosn)
  356.                END;
  357.             INC(WritePosn)
  358.          END
  359.    END;
  360.    p^[WritePosn] := 0;
  361.    MOVE(p^[0],p^[1],WritePosn + 1);
  362.    p^[0] := RegBasicComp
  363. END;
  364.  
  365. {----------------------------------------------------------------------------}
  366.  
  367. PROCEDURE TStorage.DeCompress;
  368. VAR   p         : PBuffer;
  369.       ReadPosn  : WORD;
  370.       Count     : WORD;
  371.       Total     : WORD;
  372. BEGIN
  373.    p := PBuffer(@Buf);
  374.    ReadPosn := 0;
  375.    Total := 0;
  376.    WHILE (p^[Total + 1] <> 0) DO
  377.       INC(Total);
  378.    IF p^[0] = RegBasicComp THEN
  379.       BEGIN
  380.          MOVE(p^[1],p^[0],Total);
  381.          p^[Total] := 0;
  382.          WHILE (p^[ReadPosn] <> 0) AND (ReadPosn < SholdBufLen) DO BEGIN
  383.             CASE p^[ReadPosn] OF
  384.                255      : BEGIN
  385.                              Count := p^[ReadPosn + 1];
  386.                              MOVE(p^[ReadPosn + 2],p^[ReadPosn + Count],SHoldBufLen - ReadPosn - 2);
  387.                              FILLCHAR(p^[ReadPosn],Count,32);
  388.                              INC(ReadPosn,Count)
  389.                           END;
  390.                192..254 : BEGIN
  391.                              MOVE(p^[ReadPosn],p^[ReadPosn + 1],SHoldBufLen - ReadPosn);
  392.                              p^[ReadPosn] := 32;
  393.                              DEC(p^[ReadPosn + 1],128);
  394.                              INC(ReadPosn,2)
  395.                           END;
  396.                160..191 : BEGIN
  397.                              MOVE(p^[ReadPosn],p^[ReadPosn + 1],SHoldBufLen - ReadPosn);
  398.                              p^[ReadPosn + 1] := 101;
  399.                              DEC(p^[ReadPosn],64);
  400.                              INC(ReadPosn,2)
  401.                           END;
  402.  
  403.                000..159 : INC(ReadPosn)
  404.             END
  405.          END
  406.       END
  407. END;
  408.  
  409. {----------------------------------------------------------------------------}
  410.  
  411. DESTRUCTOR TStorage.Done;
  412. VAR   TFile : FILE;
  413.       PLink : PList;
  414. BEGIN
  415.    IF (SHoldBuf <> NIL) AND (SHoldBufLen > 0) THEN
  416.       FREEMEM(SHoldBuf,SHoldBufLen);
  417.    TBufStream.Done;
  418.    IF SCleanName <> '' THEN
  419.       BEGIN
  420.          ASSIGN(TFile,SFileName);
  421.          ERASE(TFile);
  422.          ASSIGN(TFile,SCleanName);
  423.          RENAME(TFile,SFileName);
  424.          SCleanName := ''
  425.       END;
  426.    WHILE SCleanIndex <> NIL DO BEGIN
  427.       PLink := SCleanIndex;
  428.       SCleanIndex := PLink^.Next;
  429.       FREEMEM(PLink,SIZEOF(LList))
  430.    END
  431.  
  432. END;
  433.  
  434. {----------------------------------------------------------------------------}
  435.  
  436. END.
  437.  
  438. {  --------------------------    TEST PROGRAM ------------------------ }
  439.  
  440. Program StorageTest;
  441.  
  442. { This program will demonstrate the ability to save and restore text info
  443.   in an indexed file that is also Network aware. This should be interesting
  444.  
  445.   Note that the information both stored and retrived are limited to 65530
  446.   characters in length.  In the current version, this will require you to
  447.   have somewhere on your heap that much space. In the future this routine
  448.   will be made EMS aware so that it will grab the best option for heap
  449.   storage and manipulation out there...
  450.  
  451.   The OBJECT TStorage is a Child of the BufStream Object.  This means that
  452.   it still retains all the lower level stuff from BufStream, DOSStream, and
  453.   TStream if you have some sort of use for that.
  454.  
  455.   The routines provided are as follows:
  456.  
  457.   TStorage.Init(FNameStr, Mode, BufSize)
  458.       This routine will initialize the file that you are going to be reading
  459.       from or writing to.  You can use the stCreate, stOpenWrite, stOpenRead,
  460.       or stOpen as your mode.  If you use the stCreate, the system will write
  461.       over your previous file.  If you use stOpenWrite, you can ONLY write
  462.       to the file, you cannot do reads and visa-versa with stOpenRead.  If
  463.       you use stOpen, then you can do both operations at the same time.
  464.  
  465.       This is another item that in the future will be changed to do record
  466.       locking of the specified section you are writing to so that other
  467.       users on a network can read from the various other parts of the file.
  468.  
  469.       The BufSize defines the internal buffer size that the system will use
  470.       to buffer your I/O reads.  Borland recommends around 1024 for standard
  471.       usage.  You might make it bigger or smaller depending on your needs.
  472.  
  473.   TStorage.WriteMsg(Buf)
  474.       This takes a buffer that you define that is NULL terminated (there is
  475.       a #0 at the end of your text) and will write it out to the end of the
  476.       file after running the buffer thru the internal compression routine
  477.       (see TStorage.Compress). It will also set an internal variable
  478.       TStorage.SIndex that is your key to retrieving this body of text.
  479.  
  480.   TStorage.ReadMsg(Buf : PCharBuf; Index)
  481.       This is how you retrieve your text.  You pass the index that you got
  482.       earlier from TStorage.SIndex to this routine and it will pass you a
  483.       buffer that is defined as an array of characters [0..whatever] with
  484.       the string being NULL terminated.  NOTE:  If the index that you pass
  485.       is not the beginning of a stored pattern, the ReadBuf routine will
  486.       assume that you are reading a STANDARD text file and will rewind
  487.       and read the ENTIRE file into the buffer.  This is how you can use
  488.       the same routine to read normal text files as well as those created
  489.       by this Object.  If the message was deleted by the DeleteMsg routine,
  490.       you will get an errorlevel of 100 (Disk Read Error) returned to you
  491.       from the function.
  492.  
  493.   TStorage.DeleteMsg(Index)
  494.       This function does not actually delete the message out of the stream
  495.       as this would then mess up all subsequent index pointers.  Instead, it
  496.       changes the compression routine variable to $FF indicating that the
  497.       message is no longer valid.  To actually take the messages out of the
  498.       stream, you need to use the CleanUpMsg procedure.
  499.  
  500.   TStorage.CleanUpMsg
  501.       This procedure will scan the message stream, and re-write it out to a
  502.       seperate file leaving out all the deleted messages.  It then creates
  503.       a linked list of the old indexes and their new values.  This is then
  504.       used by you, the user, to change all your old saved index values.
  505.       NOTE:  Make sure that you do the index change BEFORE calling the
  506.       TStorage.Done routine as this will remove your list from memory and
  507.       all your pointers will be subsiquently screwed up.  If there is a
  508.       problem and you need to restore the previous file, you can rename
  509.       .$$$ file back to your filename.  The .$$$ file is not deleted until
  510.       the TStorage.Done is called.
  511.  
  512.   TStorage.NewIndex(Index) : LONGINT
  513.       When you call this routine with an old index number, it will return
  514.       to you the new index reference number. You'll get a -1 if the system
  515.       cannot fine an original index number.  To use this, you can scan
  516.       through your recorded indexes in your data file sequentially and call
  517.       this routine with each one you get.  Then replace the old value with
  518.       the new value.  If you get a -1 as your return, then the old message
  519.       was either originally deleted or lost to the system.  This will ALWAYS
  520.       return a -1 if you haven't made a VALID call to TStorage.CleanUpMsg.
  521.       It will also reset after a TStorage.Done has been executed.  Make sure
  522.       that you use this after the TStorage.CleanUpMsg routine if you want
  523.       to retain the changes made.
  524.  
  525.   TStorage.DeleteCleanUp
  526.       If you decide that for some reason something went wrong somewhere and
  527.       everything is screwed up, you can prevent TStorage.Done from replacing
  528.       your original msg file by calling this routine.  It will remove the
  529.       .$$$ file from the disk and clear out all TStorage.NewIndex references.
  530.  
  531.   TStorage.Compress(Buf)
  532.       This is a compression routine that is VERY rudimentary.  I whipped
  533.       this up in an hour or so just to demonstrate how it works.  You can
  534.       create a child object and replace the compress and decompress routines
  535.       with something more efficient if you'd like.  All you need to do is
  536.       create a new RegComp variable other than 1 and make sure that your
  537.       compression routine will downwardly call mine if the numbers don't
  538.       match.  This way you can read files that were created with any
  539.       compression routine that is in the line.
  540.  
  541.   TStorage.DeCompress(Buf)
  542.       Same as the compression except that this goes backwards.  Again, this
  543.       is a basic one that I whipped together in a matter of minutes so don't
  544.       be too impressed by it
  545.  
  546.   TStorage.Done
  547.       Here is where you clean up all the messes, close all the files, and
  548.       return all the used heap back.  Remember to call this when your done
  549.       using the routines
  550.  
  551.   ERRORS Returned
  552.       When you check the TStorage.Status Integer, if you do not get an stOk
  553.       returned, then something went wrong.  To identify it from this Unit,
  554.       You can check TStorage.Status against stStoreError.  Errors also
  555.       included are stStoreReadErr, stStoreWriteErr, and stStoreUnknownErr.
  556.       These are stored in the TStorage.ErrorInfo location.
  557.  
  558.   ---------------------------------------------------------------------------
  559.  
  560.   These routines were originally designed as a message storage routine for a
  561.   new BBS system message base that we are putting together, however we have
  562.   used this storage format for a varity of purposes as you can store variable
  563.   length messages to one file and only have to keep track of an index.  It
  564.   also attempts to save on disk space which is ALWAYS at a premium around
  565.   here.
  566.  
  567.   If you have any suggestions or improvments on this file or its usage, or
  568.   would just like to chat, you can reach me at the following:
  569.  
  570.         Marcos R. Della
  571.         5084 Rincon Ave.
  572.         Santa Rosa, CA 95409
  573.  
  574.         CIS: 71675,765
  575.  
  576.   ---------------------------------------------------------------------------}
  577.  
  578. Uses Dos, Crt, Storage, Objects;
  579.  
  580. VAR   T   : TStorage;
  581.       st1 : STRING;      {Kind of a pseudo buffer}
  582.       st2 : STRING;      {Another pseudo buffer}
  583.       st3 : STRING;
  584.       p   : PCharBuf;    {Pointer to the return character buffer}
  585.  
  586.       idx1   : LONGINT;
  587.       idx2   : LONGINT;
  588.       idx3   : LONGINT;
  589.       loop   : WORD;
  590.       ch     : CHAR;
  591. BEGIN
  592.    CLRSCR;
  593.    st1 := 'Now is the time for all good men to come to the aid of their '
  594.         + 'country before the last of the Mohecians take over the world as '
  595.         + 'we now know it.  This might be a very detrimental accident if '
  596.         + 'it is allowed to happen' + #0;
  597.    st2 := 'This is a message that will test the deletion function.' + #0;
  598.    st3 := 'This message will survive the compression and deletion!' + #0;
  599.  
  600.    T.Init('TESTFILE.DAT',stOpenWrite,512);
  601.    IF T.ErrorInfo = 2 THEN  {File Does Not Exist}
  602.       BEGIN
  603.          T.Done;
  604.          T.Init('TESTFILE.DAT',stCreate,512)
  605.       END;
  606.    WriteLn('Filename:   ',T.SFileName);
  607.    WriteLn('Mode:       ',T.SMode);
  608.  
  609.    T.WriteMsg(st1[1]);    {Our actual buffer is from 1..till we hit the NULL}
  610.    IF T.Status <> stOk THEN    {Do your real error checking here if you are}
  611.       T.Reset;                 {really interested}
  612.    idx1 := T.SIndex;
  613.    WriteLn('1st Index:  ',idx1);
  614.  
  615.    T.WriteMsg(st2[1]);
  616.    IF T.Status <> stOk THEN
  617.       T.Reset;
  618.    idx2 := T.SIndex;
  619.    Writeln('2nd Index:  ',idx2);
  620.  
  621.    T.WriteMsg(st3[1]);
  622.    IF T.Status <> stOk THEN
  623.       T.Reset;
  624.    idx3 := T.SIndex;
  625.    Writeln('3nd Index:  ',idx3);
  626.  
  627.    WriteLn;
  628.    T.DeleteMsg(idx2);
  629.    WriteLn('First Deletion Attempt (Write Only):   ',T.ErrorInfo);
  630.    IF T.Status <> stOk THEN
  631.       T.Reset;
  632.    T.Done;
  633.  
  634.    T.Init('TESTFILE.DAT',stOpen,128);
  635.    T.DeleteMsg(idx2);            {Must be open for read/write!}
  636.    WriteLn('Second Deletion Attempt (Read/Write):  ',T.ErrorInfo);
  637.    IF T.Status <> stOk THEN
  638.       T.Reset;
  639.  
  640.    T.ReadMsg(p,idx2);
  641.    WriteLn('Attempt to re-read:                    ',T.ErrorInfo);
  642.    IF T.Status <> stOk THEN
  643.       T.Reset;
  644.    Write('"');
  645.    Loop := 0;
  646.    WHILE p^[Loop] <> #0 DO BEGIN
  647.       Write(p^[Loop]);
  648.       INC(Loop)
  649.    END;
  650.    WriteLn('"');
  651.    Write('Cleaning up the deletion files.   Error returned: ');
  652.    T.CleanUpMsg;
  653.    WriteLn(T.ErrorInfo);
  654.    WriteLn('Re-Index of #1 (Old/New):   ',idx1,'/',T.NewIndex(idx1));
  655.    WriteLn('Re-Index of #2:             ',idx2,'/',T.NewIndex(idx2));
  656.    WriteLn('Re-Index of #3:             ',idx3,'/',T.NewIndex(idx3));
  657.    WriteLn;
  658.    WriteLn('Removing Cleanup stuff and restoring old indexes');
  659.    T.DeleteCleanUp;
  660.    T.Done;
  661.  
  662.    T.Init('TESTFILE.DAT',stOpenRead,128);
  663.    T.ReadMsg(p,idx1);
  664.    WriteLn('Test that is being read back from the file:');
  665.    WriteLn('---------------Index 1----------------------------');
  666.    Loop := 0;
  667.    WHILE p^[Loop] <> #0 DO BEGIN
  668.       Write(p^[Loop]);
  669.       INC(Loop)
  670.    END;
  671.    WriteLn;
  672.    WriteLn;
  673.  
  674.    T.ReadMsg(p,idx3);
  675.    WriteLn('---------------Index 3----------------------------');
  676.    Loop := 0;
  677.    WHILE p^[Loop] <> #0 DO BEGIN
  678.       Write(p^[Loop]);
  679.       INC(Loop)
  680.    END;
  681.    T.Done;
  682.  
  683.    WriteLn;
  684.    WriteLn('-------------------------------------------');
  685.    WriteLn('If you want to see what the compressed text looks like');
  686.    WriteLn('then use a listing utility to list the file ',T.SFilename);
  687.    WriteLn;
  688.    WriteLn('Press a key to read a STANDARD text file');
  689.    ch := READKEY;
  690.    IF ch = #0 THEN
  691.       ch := READKEY;
  692.    CLRSCR;
  693.  
  694.    T.Init('TEST.PAS',stOpenRead,1024);
  695.    T.ReadMsg(p,0);
  696.    Loop := 0;
  697.    WHILE p^[Loop] <> #0 DO BEGIN
  698.       Write(p^[Loop]);
  699.       INC(Loop)
  700.    END;
  701.    WriteLn;
  702.    T.Done;
  703. END.
  704.  
  705.